package com.qfjy.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName ProctectFilter
 * @Description TODO
 * @Author guoweixin
 * @Date 2022/3/22
 * @Version 1.0
 */
@Slf4j
@WebFilter(urlPatterns = {"/**"})
@Component
public class ProctectFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("进入doFilter 请求方法----》过滤器---》");

        HttpServletRequest request= (HttpServletRequest) servletRequest;
        HttpServletResponse response= (HttpServletResponse) servletResponse;
        // 防止恶意攻击的方法（方法重构）
       Map<String,Object> map=this.proctect(request,response);
        if((boolean)map.get("flag")==false){
            //返回的ajax数据
            //剩余锁定时间
           long timeOut= (long) map.get("timeOut");
            this.responseBody(request,response,timeOut);

            return;
        }

        //继续执行目标方法
        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Autowired
    private JedisPool jedisPool;

    /** 设置过期时间*/
    static final long PROCTECT_IP_SECONDS=10;
    /**锁定用户访问时间*/
    static final long PROCTECT_LOCK_IP_SECONDS=40;
    /**
     需求逻辑文档：
     用户每次访问服务器地址时，后台都需要进行计数操作。

     1、用户访问服务器地址时，（获得用户的IP地址）  request.getRemoteAddr();
     2、生成根据ip的redis key
     3、进行赋值(redis) incr redis ip key
     4、并进行设置过期时间 2秒钟。
     */

    public Map proctect(HttpServletRequest request,HttpServletResponse response){
       Map<String,Object> map=new HashMap<>();
        map.put("timeOut",0);
        map.put("flag",true);
        //得到用户访问IP地址
        String ip=request.getRemoteAddr();
        //生成redis key
        String key="proctect:"+ip;
        String lockKey="proctect:lock:"+ip;
        Jedis jedis=jedisPool.getResource();

        //锁定全局KEY存在
        if(jedis.exists(lockKey)){

            long secondsTimeNum=jedis.ttl(lockKey);

            jedis.close();
            log.info("因恶意该问，已被锁定");
            map.put("timeOut",secondsTimeNum);
            map.put("flag",false);
            return map;
        }


        //proctect:ip +1
        long count=jedis.incr(key);
        //如果是第一次访问，给该KEY进行过期时间的设置
        if(count==1){
            jedis.expire(key,PROCTECT_IP_SECONDS);
        }
        //（例如：2秒最多访问大于3次），锁定IP（1分钟内）。
        if(count>3){
            /**锁定 key并限制用户访问*/

            jedis.set(lockKey,ip);
            jedis.expire(lockKey,PROCTECT_LOCK_IP_SECONDS);
            jedis.close();
            map.put("timeOut",PROCTECT_LOCK_IP_SECONDS);
            map.put("flag",false);
            return map;
        }

        return map;
    }

    /**
     * 用来返回ajax
     * @param request
     * @param response
     */
    public void  responseBody(HttpServletRequest request,HttpServletResponse response,long timeOut){
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Map<String, String> map = new HashMap<>();
        map.put("status", "禁止恶意攻击访问,剩余锁定时间（秒）:"+timeOut);
        writer.write(map.toString());
    }
}
